`timescale 1 ns / 1 ps
module tb
(

);

parameter PERIOD = 20 ;
parameter LENGTH = 10'd33 ;


reg      pll_rst;
reg      test_rst;
wire   	tx_rx;
wire		clk_10M;
wire		pll_locked;


wire     rst=!pll_locked;


wire		[1:0]	 tx_rdy;

reg		[15:0] tx_init_data;
reg      [15:0] tx_data;
reg		[9:0]  frame_len;//frame length 
reg		[4:0]  frame_st;
reg             frame_end;


reg				 tx_nce;
reg				 tx_nwe;
reg				 tx_noe;
reg	  [8:0]   tx_rd_addr;
reg             tx_rd_ab;

wire	  [15:0]  tx_rd_data;
reg	  [15:0]  tx_rd_data_r;
				 

wire    [9:0]   tx_rd_addr_ab=  {tx_rd_ab,tx_rd_addr};


reg inclk ;

   initial begin
      inclk = 1'b0;
      #(PERIOD/2);
      forever
         #(PERIOD/2) inclk = ~inclk;
   end


reg test_clk ;

   initial begin
	   test_clk = 1'b1;
      #6 ;
		test_clk = 1'b0;
      #(PERIOD/3);
      forever
         #(PERIOD/3) test_clk = ~test_clk;
   end

	

	initial begin
	test_rst=1'b1;
	pll_rst=1'b1;
	tx_data=0;
	#50 pll_rst=1'b0;
	test_rst=1'b0;
	end
	
	
	
	reg					tx_en;  //tx_ena
	reg					rx_en;  //
	reg					tx_ack;
	reg					rx_ack;
	
	reg	[5:0]			cpu_high_addr;
	reg 	[2:0]			schedule_st;
	
	
always@(posedge test_clk or posedge test_rst)
if(rst) begin
	tx_en<=1'b0;
	rx_en<=1'b0;
	cpu_high_addr<=6'd0;
	schedule_st<=0;
end
else case(schedule_st)
0:begin
	tx_en<=1'b1;
	cpu_high_addr<=6'd0; //0-1023
	schedule_st<=1;
end
1:begin
	//tx_en<=1'b1;
	if(tx_ack) begin
	 tx_en<=1'b0;
	schedule_st<=2;
	end
end
2:begin
   cpu_high_addr<=6'd1;  //1024-2047
	rx_en<=1'b1;
	schedule_st<=3;
  end
3:begin
	if(rx_ack) begin
	 rx_en<=1'b0;
	 schedule_st<=0;
	end
  end
default:schedule_st<=0;
endcase
	
	
	
always@(posedge test_clk or posedge test_rst)
if(rst) begin
   tx_rd_ab	  	<=1'b0;
	tx_rd_addr 	<=511;
	tx_nce	  	<=1'b1;
	tx_noe	  	<=1'b1;
	tx_nwe	  	<=1'b1;
	frame_len  	<=0;
	tx_data	  	<=0;
	frame_end  	<=1'b0;
	tx_ack	  	<=1'b0;
	tx_init_data<=0;
	tx_rd_data_r<=0;
	frame_st	  	<=0;  //frame state machine
end
else  case(frame_st)
0:begin
	tx_rd_ab	   <=1'b0;
	tx_rd_addr  <=511;
	tx_nce		<=1'b1;
	tx_noe		<=1'b1;
	tx_nwe		<=1'b1;		
	tx_data		<=0;
	frame_end	<=1'b0;
	tx_ack	  	<=1'b0;
	tx_init_data<=0;
	tx_rd_data_r<=0;
	frame_st		<=1;
   end

1:begin
   tx_nce		<=1'b1;
	tx_noe		<=1'b1;
	tx_nwe		<=1'b1;	
	tx_rd_addr  <=511;
	tx_rd_data_r<=0;
   if(tx_en)
	frame_st		<=2;
  end
	
2:begin  //start 1
   tx_nce		<=1'b0;
	tx_noe		<=1'b1;	
	frame_st		<=3;
end

3:begin 
   tx_nce		<=1'b0;
	tx_noe		<=1'b0;
	frame_st		<=4;
end

4:begin 
   tx_nce		<=1'b0;
	tx_noe		<=1'b0;
	frame_st		<=5;
end
5:begin 
   tx_nce		<=1'b0;
	tx_noe		<=1'b0;
	frame_st		<=6;
end
6:begin 
   tx_nce		<=1'b0;
	tx_noe		<=1'b0;
	frame_st		<=7;
end
7:begin 
   tx_nce		<=1'b0;
	tx_noe		<=1'b0;
	frame_st		<=8;
end
8:begin 
   tx_nce		<=1'b0;
	tx_noe		<=1'b1;
	tx_rd_data_r<=tx_rd_data;
	frame_st		<=9;
end
9:begin  //start 1
   tx_nce		<=1'b1;
	tx_noe		<=1'b1;	
  if(tx_rd_data_r[15])begin
	frame_st		<=10;
  end	
  else begin
  frame_st		<=11;
  end
  
end
10:begin 
   tx_nce		<=1'b1;
	tx_noe		<=1'b1;
	frame_st		<=22;
end
11:begin 
   tx_nce		<=1'b1;
	tx_noe		<=1'b1;
	frame_st		<=12;
end

12:begin  //start 1
	frame_len	<=frame_len+2'd2;
	tx_nce		<=1'b0;
	tx_nwe		<=1'b1;
	tx_rd_addr  <=0;
	frame_st		<=14;
	tx_data		<=tx_init_data;
end

13:begin
	frame_len	<=frame_len+2;
	tx_data		<=tx_data+1;
	tx_rd_addr  <=tx_rd_addr+1'b1;
	tx_nce		<=1'b0;
	tx_nwe		<=1'b1;
	frame_st		<=14;
	if(frame_len>=LENGTH)begin
		frame_end<=1'b1;
		tx_data		<={1'b1,5'b0,LENGTH}; 
		tx_rd_addr  <=14'd511;
	end
end
14:begin
	frame_st		<=15;
	tx_nce		<=1'b0;
	tx_nwe		<=1'b0;
	end
15:begin
	frame_st		<=16;
	tx_nce		<=1'b0;
	tx_nwe		<=1'b0;	
   end
	
16:begin
	frame_st		<=17;
	tx_nce		<=1'b0;
	tx_nwe		<=1'b0;	
   end	
17:begin
	frame_st		<=18;
	tx_nce		<=1'b0;
	tx_nwe		<=1'b0;	
   end	
18:begin
   frame_st		<=19;
	tx_nce		<=1'b0;
	tx_nwe		<=1'b1;	
  end	
19:begin
	frame_st		<=20;
	tx_nce		<=1'b1;
	tx_nwe		<=1'b1;	
   end 
20:begin
	frame_st		<=21;
	tx_nce		<=1'b1;
	tx_nwe		<=1'b1;	
   end 
21:begin
	  if(frame_end) begin
		  frame_st		<=22;
		  frame_len		<=0;
		   tx_init_data<=tx_init_data+1'b1;
		  tx_rd_ab	   <=~tx_rd_ab;
		  tx_rd_addr   <=14'd511;
	  end
		else
		frame_st		<=13;
end
22:begin
    frame_end	<=1'b0;
	 tx_ack		<=1'b1;
	 frame_st	<=23;
	end
23:begin
	 tx_ack		<=1'b0;
	 frame_st	<=1;
	end
default:frame_st<=0;
endcase














reg				 rx_nce;
reg				 rx_noe;
reg				 rx_nwe;
wire		[15:0] rx_data;
reg		[15:0] rx_data_cpu;
reg		[15:0] rx_data_out;
wire				 rx_rdy;	
reg		[8:0]  rx_addr_r; 
reg				 rx_toggle;
reg		[9:0]  rx_len;
reg      [4:0]  recv_st;

wire		[9:0] rx_addr={rx_toggle,rx_addr_r};


always@(posedge test_clk or posedge test_rst)

if(test_rst) begin
	rx_nce		<=1'b1;
	rx_noe		<=1'b1;
	rx_nwe		<=1'b1;
	rx_toggle	<=1'b0;
	rx_addr_r	<=511;  
	rx_len		<=0;
	rx_data_out	<=0;
	rx_ack		<=0;
	rx_data_cpu	<=0;
	recv_st		<=0;
end

else case(recv_st)
0: begin
	rx_nce		<=1'b1;
	rx_noe		<=1'b1;
	rx_nwe		<=1'b1;
	rx_toggle	<=1'b0;
	rx_addr_r	<=511; 
	rx_len		<=0;
	rx_data_out	<=0;
	rx_ack		<=0;
	rx_data_cpu	<=0;
	recv_st	<=1;
end

1:begin
	rx_nce		<=1'b1;	
	rx_noe		<=1'b1;
	rx_nwe		<=1'b1;
	rx_len		<=0;
	rx_ack		<=0;
	rx_data_cpu	<=0;
   if(rx_en) begin
		rx_nce	<=1'b0;	
		recv_st	<=2;
	end
  end

2:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;
	rx_len	<=0;
	recv_st	<=3;
  end
3:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;
	rx_len	<=0;
	recv_st	<=4;
   end  
4:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;
	rx_len	<=0;
	recv_st	<=5;
   end 
5:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;
	rx_len	<=0;
	recv_st	<=6;
   end 
6:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;
	rx_len	<=0;
	recv_st	<=7;
   end 
7:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b1;
	rx_nwe	<=1'b1;
	rx_data_cpu	<=rx_data;
	rx_len	<=0;
	recv_st	<=8;
  end
8:begin
	rx_nce	<=1'b1;	
	rx_noe	<=1'b1;
	rx_nwe	<=1'b1;
	rx_len	<=0;
	recv_st	<=9;
   end 
9:begin
	rx_nce	<=1'b1;	
	rx_noe	<=1'b1;
	rx_nwe	<=1'b1;
	rx_len	<=0;
	recv_st	<=10;
   end 		
10:begin
		rx_nce	<=1'b1;	
		rx_noe	<=1'b1;
		rx_nwe	<=1'b1;
		if(rx_data_cpu[15]) begin
			rx_len	<=rx_data_cpu[9:0];
			rx_addr_r	<=rx_addr_r+1;
			recv_st	<=11;
		end
		else begin
			rx_addr_r	<=511;
			recv_st		<=27;
		end
	end
11:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b1;
	rx_nwe	<=1'b1;
	recv_st	<=12;
   end
12:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;
	
	recv_st	<=13;
   end
13:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;
	
	recv_st	<=14;
   end	
14:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;
	
	recv_st	<=15;
   end
15:begin
	rx_nce	<=1'b0;	
	rx_noe	<=1'b0;
	rx_nwe	<=1'b1;	
	recv_st	<=16;
   end			
16:begin
	rx_nce		<=1'b0;	
	rx_noe		<=1'b1;
	rx_nwe		<=1'b1;
	rx_data_cpu	<=rx_data;
	recv_st		<=17;
end
17:begin
	rx_nce		<=1'b1;	
	rx_noe		<=1'b1;
	rx_nwe		<=1'b1;
	recv_st		<=18;
end
18:begin
	rx_nce		<=1'b1;	
	rx_noe		<=1'b1;
	rx_nwe		<=1'b1;
	if(rx_len==1)
	rx_len		<=0;
	else
	rx_len		<=rx_len-2'd2;
	rx_data_out	<=rx_data_cpu;
	recv_st		<=19;
end
19:begin
	rx_nce		<=1'b1;	
	rx_noe		<=1'b1;
	rx_nwe		<=1'b1;
	rx_addr_r<=rx_addr_r+1;
	if(rx_len==0) begin
		rx_addr_r	<=511;
		recv_st		<=20;
		end
	else 
		recv_st		<=11;
end

20:begin
	rx_nce		<=1'b0;	
	rx_nwe		<=1'b0;
	recv_st		<=21;
end
21:begin
	rx_nce		<=1'b0;	
	rx_nwe		<=1'b0;
	recv_st		<=22;
end

22:begin
	rx_nce		<=1'b0;	
	rx_nwe		<=1'b0;
	recv_st		<=23;
end
23:begin
	rx_nce		<=1'b0;	
	rx_nwe		<=1'b0;
	recv_st		<=24;
end
24:begin
	rx_nce		<=1'b0;	
	rx_nwe		<=1'b1;
	recv_st		<=25;
end

25:begin
	rx_nce		<=1'b1;	
	rx_nwe		<=1'b1;
	recv_st		<=26;
end
26:begin
	rx_nce		<=1'b1;	
	rx_nwe		<=1'b1;
	rx_toggle<= ~rx_toggle;
	recv_st		<=27;
end

27:begin	
	//if(rx_rdy) begin
	   rx_ack<=1'b1;
		recv_st	<=28;
	end
28:begin	
	//if(rx_rdy) begin
	    rx_ack<=1'b0;
		recv_st	<=1;
  end
 default:recv_st	<=0;
endcase






wire [15:0]   cpu_addr;
wire 			  cpu_nce;
wire			  cpu_noe;
wire			  cpu_nwe;
wire [15:0]   cpu_data;

assign		  cpu_addr =tx_en?{cpu_high_addr,tx_rd_addr_ab}:

								(rx_en?{cpu_high_addr,rx_addr}:16'hZZZZ);

assign		  cpu_nce 	=tx_en?tx_nce:(rx_en?rx_nce:1'b1);
assign		  cpu_noe 	=tx_en?tx_noe:(rx_en?rx_noe:1'bZ);
assign        cpu_nwe 	=tx_en?tx_nwe:(rx_en?rx_nwe:1'bZ);
assign		  cpu_data	=tx_en?((~tx_nwe)?tx_data:16'hZZZZ):
								(rx_en?((~rx_nwe)?16'h0000:16'hZZZZ):16'hZZZZ);
assign		  tx_rd_data=(tx_en&(~cpu_noe))?cpu_data:16'h0000;								
assign		  rx_data	=(rx_en&(~cpu_noe))?cpu_data:16'h0000;	


lvds_top   lvds_top_inst
(
.inclk			(inclk),
.pll_rst			(pll_rst),
.cpu_nce			(cpu_nce),
.cpu_noe			(cpu_noe),
.cpu_nwe			(cpu_nwe),
.cpu_addr		(cpu_addr),
.cpu_data		(cpu_data),
.tx_rdy			(tx_rdy),
.tx				(tx_rx),
.rx				(tx_rx),
.clk_10M			(clk_10M),
.pll_locked		(pll_locked)

);


endmodule

